Das Ziel ist es, aus dem Datacamp Datensatz Soccer Data, welcher Daten aus der höchsten englischen Fussballdivision beinhaltet, folgende Fragestellung / Hypothese zu beantworten:
Die Manschaft, die zur Halbzeit vorne liegt, gewinnt mit einer Chance von mindestens 75% das Spiel. Falls zur Halbzeit unentschieden ist, gewinnt eher das Heimteam mit einer Chance von mindestens 33.4%.
Als Einführung werden wir auf Datacamp folgende Kurse durchgehen:
# Import libraries
library("plotly")
library("plyr")
library("dplyr")
library("forcats")
library("RColorBrewer")
# List files in folder "data"
files <- list.files(path="./data/", pattern=NULL, all.files=FALSE, full.names=TRUE)
# Create Dataframe with all csv from years 2015-2019
df <- ldply(.data = files, .fun = read.csv)
df
# Create dataframe for halftime & fulltime results and count frequency
df_htr <- df %>% count(HTR)
df_ftr <- df %>% count(FTR)
# Halftime
df_htr
# Fulltime
df_ftr
Hier zählen wir, wie oft das Heim - und Auswärtsteam zur Halb - und Vollzeit gewinnen oder ob das Spiel unentschieden ist.
A = Auswärtsteam gewinnt
D = Unentschieden
H = Heimteam gewinnt
# Create dataframe with halftime & fulltime result frequency
df_results <- data.frame(c("Away win", "Draw", "Home win"), c(df_htr$n), c(df_ftr$n))
# Rename column headers
col_headings <- c('Result','Halftime','Fulltime')
names(df_results) <- col_headings
df_results
In diesen beiden Dataframes sieht man deutlich, dass zur Halbzeit meistens ein Unentschieden steht. Gegen Ende des Spiels, ist das Unentschieden aber das seltenste Resultat. Knapp 700 mal von insgesamt 1520 Spielen siegte am Ende das Heimteam. Dies entspricht rund 46%. Wir gehen davon aus, dass dies damit zu tun hat, dass beide Teams in der zweiten Halbzeit mehr riskieren, da sie lieber den Sieg forcieren und dabei eine Niederlage rauskommt, anstatt das Unentschieden über die Zeit zu bringen.
# Plot grouped bar chart to visualize halftime & fulltime results
fig <- plot_ly(
df_results, x = ~Result, y = ~Halftime, type = 'bar', name = 'Halftime Score', width = 600, height = 500) %>%
add_trace(y = ~Fulltime, name = 'Fulltime Score') %>%
layout(yaxis = list(title = 'Amount'), barmode = 'group')
fig
Die obige Erkenntnis haben wir hier noch als Barchart dargestellt. Das Heimteam gewinnt also im Schnitt viel öfters, als das Auswärtsteam.
# Merge HTR & FTR to new column 'result'
df$result <- paste(df$HTR, df$FTR)
# Example: H H = home team is winning at halftime and also wins the game at fulltime
df[,"result", drop=FALSE]
# Plot all different game progresses and their amount
df_count_results <- df %>%
count(result)
df_count_results %>%
mutate(result = fct_reorder(result, n, .desc = TRUE)) %>%
plot_ly(x = ~result, y = ~n, text = ~n, textposition = 'auto', width = 800, height = 500) %>%
add_bars() %>%
layout(xaxis = list(title = "Game Progress"),
yaxis = list(title = "Amount of Game Progresses"),
title = "How are the different game progresses distributed?")
Hier wollten wir herausfinden, wie wahrscheinlich die 9 möglichen Spielausgängen sind bevor das Spiel überhaupt beginnt. Man sieht, dass der häufigste Spielverlauf das “H H” ist. Also, dass in den meisten Spielen das Heimteam zur Halbzeit führt und die Führung bis zum Schluss halten kann. Das seltenste Resultat war, dass das Heimteam zur Pause geführt hat und das Spiel am Ende doch noch verlor. Das kam bei 1520 Speielen nur genau 27x vor.
# Group by game outcome & calculate probability in percent of all outcomes
df_count_results_prob <- df %>%
group_by(result) %>%
summarise(count_result = round(n() / nrow(df) * 100, digits = 2))
# Plot all different game progresses and their probability
df_count_results_prob %>%
mutate(result = fct_reorder(result, count_result, .desc = TRUE)) %>%
plot_ly(x = ~result, y = ~count_result, text = ~count_result, textposition = 'auto', width = 800, height = 500) %>%
add_bars() %>%
layout(xaxis = list(title = "Game Progress"),
yaxis = list(title = "Probability of Game Progress (%)"),
title = "How are the different game progresses distributed?")
Den selben Graphen wollten wir noch in Prozenten darstellen.
df_count_results %>%
plot_ly(labels = ~result, values = ~n, textinfo = "text", text = ~n) %>%
add_pie(hole = 0.4, color = I("white")) %>%
layout(xaxis = list(title = "Game Progress"),
yaxis = list(title = "Probability %"),
title = "How are the different game progresses distributed?")
Hier sind nochamls die gleichen Daten, anders dargestellt in einem Donutchart. Es ist interessant, wenn man einige Speilverläufe ausblendet.
df_count_results_prob %>%
plot_ly(labels = ~result, values = ~count_result) %>%
add_pie(hole = 0.4, color = I("white")) %>%
layout(xaxis = list(title = "Game Progress"),
yaxis = list(title = "Probability %"),
title = "What is the probability of each game progress?")
In diesem Donutchart sieht man die Verteilung nochmals anderst dargestellt.
# Calculate probability between halftime & fulltime away / draw / home results
calc_prob <- function(df1, df2) {
prob <- round((100 / nrow(df1) * nrow(df2)), digits = 2)
return(prob)
}
# Filter home teams winning at halftime
df_ht_home <- df %>%
filter(HTR == "H")
# Filter home teams winning at halftime & fulltime
df_ft_home <- df_ht_home %>%
filter(FTR == "H")
home_win_prob <- calc_prob(df_ht_home, df_ft_home)
cat("Die Wahrscheinlichkeit, dass das Heimteam gewinnt, wenn sie zur Halbzeit vorne liegen, beträgt: ", home_win_prob, "%")
Die Wahrscheinlichkeit, dass das Heimteam gewinnt, wenn sie zur Halbzeit vorne liegen, beträgt: 82.55 %
# Filter away teams winning at halftime
df_ht_away <- df %>%
filter(HTR == "A")
# Filter away teams winning at halftime & fulltime
df_ft_away <- df_ht_away %>%
filter(FTR == "A")
away_win_prob <- calc_prob(df_ht_away, df_ft_away)
cat("Die Wahrscheinlichkeit, dass das Auswertsteam gewinnt, wenn sie zur Halbzeit vorne liegen, beträgt: ", away_win_prob, "%")
Die Wahrscheinlichkeit, dass das Auswertsteam gewinnt, wenn sie zur Halbzeit vorne liegen, beträgt: 72.03 %
# Filter draw at halftime
df_ht_draw <- df %>%
filter(HTR == "D")
# Filter draw at halftime & fulltime
df_ft_draw <- df_ht_draw %>%
filter(FTR == "D")
draw_prob <- calc_prob(df_ht_draw, df_ft_draw)
cat("Die Wahrscheinlichkeit, dass ein Spiel in einem Unentschieden endet, wenn schon zur Halbzeit unentschieden war, beträgt: ", draw_prob, "%")
Die Wahrscheinlichkeit, dass ein Spiel in einem Unentschieden endet, wenn schon zur Halbzeit unentschieden war, beträgt: 36.45 %
# Filter draw at halftime & the home team winning at fulltime
df_ht_draw_ft_home_win <- df_ht_draw %>%
filter(FTR == "H")
home_win_after_ht_draw_prob <- calc_prob(df_ht_draw, df_ht_draw_ft_home_win)
cat("Die Wahrscheinlichkeit, dass das Heimteam gewinnt, wenn zur Halbzeit unentschieden war, beträgt: ", home_win_after_ht_draw_prob, "%")
Die Wahrscheinlichkeit, dass das Heimteam gewinnt, wenn zur Halbzeit unentschieden war, beträgt: 38.03 %
Bestätigung der Hypothese
Nun wollen wir aber die Wahrscheinlichkeit wissen, dass das zur Halbzeit führende Team das Spiel gewinnt. Egal ob Heim - oder Auswärtsteam.
Somit können wir aus den 2 Wahrscheinlichkeiten “home_win_prob” und “away_win_prob” unsere Hypothese wie folgt bestätigen:
# Probability that the team winning at half time wins the game
ht_ft_win_prob <- round(((home_win_prob * nrow(df_ft_home)) + (away_win_prob * nrow(df_ft_away))) / (nrow(df_ft_home) + nrow(df_ft_away)), digits = 2)
cat("Wahrscheinlichkeit, dass das Team, welches zur Halbzeit führt, den Match gewinnt: ", ht_ft_win_prob, "%")
Wahrscheinlichkeit, dass das Team, welches zur Halbzeit führt, den Match gewinnt: 78.41 %
fig <- plot_ly(
y = c("Home wins after leading at HT", "Away wins after leading at HT", "Draw at FT & HT"),
x = c(home_win_prob, away_win_prob, draw_prob),
type = "bar"
)
#label title and axis
fig <- fig %>% layout(title = "Game Progress Overview",
xaxis = list(title = "Probability"))
#print figure
fig
Fazit
Wir konnten unsere Hypothese bestätigen. Das Team, welches zur Halbzeit vorne liegt, gewinnt zu 78.41%. Ebenfalls ist die Wahrscheinlichkeit, dass das Heimteam gewinnt, nach einem Unentschieden zur Halbzeit, 38.03%. Wir hätten diesen Wert etwas höher erwartet und sind über das Ergebnis überrascht.
2. Hypothese:
Das Heimteam hat mehr Schüsse als das Auswärtsteam, aber das Auswertsteam ist effizienter.
# def variables
n_shots <- df %>%
summarise(
Home = sum(HS),
Away = sum(AS)
)
n_shots
Der erste Teil der Hypothese ist somit bestätigt. Die Heimteams haben viel mehr schüsse aufs Tor. Im Durchschnitt sind es bei 1520 Spielen also 14.01 Schüsse des Heimteams und 11.21 Schüsse des Auswertsteams.
# Plot Fulltime Home Shots vs Home Goals
p1 <- df %>%
plot_ly(x = ~FTHG, y = ~HS, coloraxis = 'coloraxis') %>%
add_histogram2d(nbinsy = 40)
# Plot Fulltime Away Shots vs Away Goals
p2 <- df %>%
plot_ly(x = ~FTAG, y = ~AS, coloraxis = 'coloraxis') %>%
add_histogram2d(nbinsy = 40)
# Add both plots together to build subplot
subplot(p1, p2, nrows = 1, shareX = FALSE, shareY = FALSE) %>%
layout(
title = "Goals vs Shots Overview",
xaxis = list(title = "Home Goals"),
xaxis2 = list(title = "Away Goals"),
yaxis = list(title = "Home Shots"),
yaxis2 = list(title = "Away Shots"),
coloraxis=list(colorscale='Jet')
)
Anhand des Plots oben ist gut zu sehen, dass das Heimteam oftmals 1-2 Tore schiesst und 9-16 Torschüsse aufweist. Beim Auswärtsteam siehts etwas anders aus; Sie schiessen eher 0-1 Tor und weisen dabei 6-11 Torschüsse auf.
# Fit the regression model of Fulltime Home Goals on Home Shots
m <- lm(FTHG ~ HS, data = df)
# Create the scatterplot with smoother
df %>%
plot_ly(x = ~HS, y = ~FTHG) %>%
add_markers(showlegend = FALSE) %>%
add_lines(y = ~fitted(m)) %>%
layout(title = "Expectet goals by home shots")
Auf diesem Plot, kann man anhand der orangen Linie sehen, wievielen Tore man erwarten kann, bei einer gewissen Anzahl Schüsse des Heimteams. Zum Beispiel: Wenn das Heimteam 25 Schüsse abgiebt, kann man im Durchschnitt mit 2.310 Toren rechnen.
# Fit the regression model of Fulltime Away Goals on Away Shots
m <- lm(FTAG ~ AS, data = df)
# Create the scatterplot with smoother
df %>%
plot_ly(x = ~AS, y = ~FTAG) %>%
add_markers(showlegend = FALSE) %>%
add_lines(y = ~fitted(m)) %>%
layout(title = "Expectet goals by away shots")
Auf diesem Plot, kann man anhand der orangen Linie sehen, wievielen Tore man erwarten kann, bei einer gewissen Anzahl Schüsse des Auswertsteams. Zum Beispiel: Wenn das Auswertsteam 25 Schüsse abgiebt, kann man im Durchschnitt mit 2.385 Toren rechnen.
df %>%
plot_ly(x = ~HS, y = ~AS, coloraxis = 'coloraxis') %>%
add_histogram2d(nbinsx = 70, nbinsy = 60) %>%
layout(coloraxis=list(colorscale='Jet'))
Anhand dieses Plots, sieht man die Verteilung der Schusshäufigkeit. In den allermeisten Spielen, geben beide Teams 10-15 Schüsse ab. Es gibt in seltenen Fällen aber auch Spiele, wo die Heimmanschaft viel, viel mehr Schüsse hat. Zb 1x hatte das Heimteam 37 Schüsse und das Auswertsteam NUR 3! Dieses Spiel war Liverpool : Everton im Jahr 2016 und Liverpool gewann 4:0.
#calculate the efficiency of the teams.
df_efficiency <- df %>%
summarise(
"Home Goals per Shot" = round(sum(FTHG) / sum(HS),digits = 3),
"Home Goals per Shot on Target" = round(sum(FTHG) / sum(HST),digits = 3),
"Away Goals per Shot" = round(sum(FTAG) / sum(AS),digits = 3),
"Away Goals per Shot on Target" = round(sum(FTAG) / sum(AST),digits = 3)
)
# Transpose dataframe
t_df_efficiency <- data.frame("Percent" = t(df_efficiency))
# Plot the efficiency in a barchart.
fig <- plot_ly(
y = c("Home Goals per Shot ", "Home Goals per Shot on Target ", "Away Goals per Shot ", "Away Goals per Shot on Target "),
x = t_df_efficiency$Percent,
type = "bar"
)
# Name the title
fig <- fig %>% layout(title = "Team Efficiency",
xaxis = list(title = "Probability"))
# Plot figure
fig
Anhand dieses Diagrams, kann man sehen, dass der zweite Teil unserer Hypothese, leider nicht stimmt. Das Heimteam ist im Durchschnitt effizienter als das Auswertsteam. Pro Schuss aufs Tor, kann das Heimteam mit 0.328 Toren rechnen. Das Auswertsteam kann pro Torschuss nur mit 0.312 Toren rechnen.
Fazit
Wir sind überrascht, dass das Heimteam etwas effizienter ist, als das Auswertsteam. Allerdings ist der Unterschied extrem knap. Was allerdings spannend zu beobachten ist, ist dass das Heimteam im Schnitt ca. 14 Schüsse hat und das Auswertsteam nur ca. 11. Achtet euch doch beim nächsten Fussballspiel darauf. Ihr könnt pro Spiel also mit ca. 25 Schüssen rechnen. Dabei ist es wahrscheinlich, dass das Heimteam das Spiel gewinnt, auch wenn zur Halbzeit noch ein Unentschieden steht.
LS0tDQp0aXRsZTogIkRhdGEgVmlzdWFsaXphdGlvbiBtaXQgUGxvdGx5Ig0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KRGFzIFppZWwgaXN0IGVzLCBhdXMgZGVtIERhdGFjYW1wIERhdGVuc2F0eiBbU29jY2VyIERhdGFdKGh0dHBzOi8vYXBwLmRhdGFjYW1wLmNvbS93b3Jrc3BhY2UvZGF0YXNldHMvZGF0YXNldC1weXRob24tc29jY2VyKSwgd2VsY2hlciBEYXRlbiBhdXMgZGVyIGjDtmNoc3RlbiBlbmdsaXNjaGVuIEZ1c3NiYWxsZGl2aXNpb24gYmVpbmhhbHRldCwgZm9sZ2VuZGUgRnJhZ2VzdGVsbHVuZyAvIEh5cG90aGVzZSB6dSBiZWFudHdvcnRlbjoNCg0KDQojIyMgRGllIE1hbnNjaGFmdCwgZGllIHp1ciBIYWxiemVpdCB2b3JuZSBsaWVndCwgZ2V3aW5udCBtaXQgZWluZXIgQ2hhbmNlIHZvbiBtaW5kZXN0ZW5zIDc1JSBkYXMgU3BpZWwuIEZhbGxzIHp1ciBIYWxiemVpdCB1bmVudHNjaGllZGVuIGlzdCwgZ2V3aW5udCBlaGVyIGRhcyBIZWltdGVhbSBtaXQgZWluZXIgQ2hhbmNlIHZvbiBtaW5kZXN0ZW5zIDMzLjQlLg0KDQoNCkFscyBFaW5mw7xocnVuZyB3ZXJkZW4gd2lyIGF1ZiBEYXRhY2FtcCBmb2xnZW5kZSBLdXJzZSBkdXJjaGdlaGVuOg0KDQotIFtJbnRlcmFjdGl2ZSBEYXRhIFZpc3VhbGl6YXRpb24gd2l0aCBwbG90bHldKGh0dHBzOi8vYXBwLmRhdGFjYW1wLmNvbS9sZWFybi9jb3Vyc2VzL2ludGVyYWN0aXZlLWRhdGEtdmlzdWFsaXphdGlvbi13aXRoLXBsb3RseS1pbi1yKQ0KDQotIFtJbnRlcm1lZGlhdGUgSW50ZXJhY3RpdmUgRGF0YSBWaXN1YWxpemF0aW9uIHdpdGggcGxvdGx5XShodHRwczovL2FwcC5kYXRhY2FtcC5jb20vbGVhcm4vY291cnNlcy9pbnRlcmFjdGl2ZS1kYXRhLXZpc3VhbGl6YXRpb24td2l0aC1wbG90bHktaW4tcikNCg0KDQpgYGB7cn0NCiMgSW1wb3J0IGxpYnJhcmllcw0KbGlicmFyeSgicGxvdGx5IikNCmxpYnJhcnkoInBseXIiKQ0KbGlicmFyeSgiZHBseXIiKQ0KbGlicmFyeSgiZm9yY2F0cyIpDQpsaWJyYXJ5KCJSQ29sb3JCcmV3ZXIiKQ0KYGBgDQoNCmBgYHtyfQ0KIyBMaXN0IGZpbGVzIGluIGZvbGRlciAiZGF0YSINCmZpbGVzIDwtIGxpc3QuZmlsZXMocGF0aD0iLi9kYXRhLyIsIHBhdHRlcm49TlVMTCwgYWxsLmZpbGVzPUZBTFNFLCBmdWxsLm5hbWVzPVRSVUUpDQoNCiMgQ3JlYXRlIERhdGFmcmFtZSB3aXRoIGFsbCBjc3YgZnJvbSB5ZWFycyAyMDE1LTIwMTkNCmRmIDwtIGxkcGx5KC5kYXRhID0gZmlsZXMsIC5mdW4gPSByZWFkLmNzdikNCg0KZGYNCmBgYA0KDQpgYGB7cn0NCiMgQ3JlYXRlIGRhdGFmcmFtZSBmb3IgaGFsZnRpbWUgJiBmdWxsdGltZSByZXN1bHRzIGFuZCBjb3VudCBmcmVxdWVuY3kgDQpkZl9odHIgPC0gZGYgJT4lIGNvdW50KEhUUikNCmRmX2Z0ciA8LSBkZiAlPiUgY291bnQoRlRSKQ0KDQojIEhhbGZ0aW1lDQpkZl9odHINCiMgRnVsbHRpbWUNCmRmX2Z0cg0KYGBgDQoNCkhpZXIgesOkaGxlbiB3aXIsIHdpZSBvZnQgZGFzIEhlaW0gLSB1bmQgQXVzd8OkcnRzdGVhbSB6dXIgSGFsYiAtIHVuZCBWb2xsemVpdCBnZXdpbm5lbiBvZGVyIG9iIGRhcyBTcGllbCB1bmVudHNjaGllZGVuIGlzdC4NCg0KLSBBID0gQXVzd8OkcnRzdGVhbSBnZXdpbm50DQoNCi0gRCA9IFVuZW50c2NoaWVkZW4NCg0KLSBIID0gSGVpbXRlYW0gZ2V3aW5udA0KDQpgYGB7cn0NCiMgQ3JlYXRlIGRhdGFmcmFtZSB3aXRoIGhhbGZ0aW1lICYgZnVsbHRpbWUgcmVzdWx0IGZyZXF1ZW5jeQ0KZGZfcmVzdWx0cyA8LSBkYXRhLmZyYW1lKGMoIkF3YXkgd2luIiwgIkRyYXciLCAiSG9tZSB3aW4iKSwgYyhkZl9odHIkbiksIGMoZGZfZnRyJG4pKQ0KDQojIFJlbmFtZSBjb2x1bW4gaGVhZGVycw0KY29sX2hlYWRpbmdzIDwtIGMoJ1Jlc3VsdCcsJ0hhbGZ0aW1lJywnRnVsbHRpbWUnKQ0KbmFtZXMoZGZfcmVzdWx0cykgPC0gY29sX2hlYWRpbmdzDQoNCmRmX3Jlc3VsdHMNCmBgYA0KSW4gZGllc2VuIGJlaWRlbiBEYXRhZnJhbWVzIHNpZWh0IG1hbiBkZXV0bGljaCwgZGFzcyB6dXIgSGFsYnplaXQgbWVpc3RlbnMgZWluIFVuZW50c2NoaWVkZW4gc3RlaHQuIEdlZ2VuIEVuZGUgZGVzIFNwaWVscywgaXN0IGRhcyBVbmVudHNjaGllZGVuIGFiZXIgZGFzIHNlbHRlbnN0ZSBSZXN1bHRhdC4gS25hcHAgNzAwIG1hbCB2b24gaW5zZ2VzYW10IDE1MjAgU3BpZWxlbiBzaWVndGUgYW0gRW5kZSBkYXMgSGVpbXRlYW0uIERpZXMgZW50c3ByaWNodCBydW5kIDQ2JS4gV2lyIGdlaGVuIGRhdm9uIGF1cywgZGFzcyBkaWVzIGRhbWl0IHp1IHR1biBoYXQsIGRhc3MgYmVpZGUgVGVhbXMgaW4gZGVyIHp3ZWl0ZW4gSGFsYnplaXQgbWVociByaXNraWVyZW4sIGRhIHNpZSBsaWViZXIgZGVuIFNpZWcgZm9yY2llcmVuIHVuZCBkYWJlaSBlaW5lIE5pZWRlcmxhZ2UgcmF1c2tvbW10LCBhbnN0YXR0IGRhcyBVbmVudHNjaGllZGVuIMO8YmVyIGRpZSBaZWl0IHp1IGJyaW5nZW4uIA0KDQpgYGB7cn0NCiMgUGxvdCBncm91cGVkIGJhciBjaGFydCB0byB2aXN1YWxpemUgaGFsZnRpbWUgJiBmdWxsdGltZSByZXN1bHRzDQpmaWcgPC0gcGxvdF9seSgNCiAgZGZfcmVzdWx0cywgeCA9IH5SZXN1bHQsIHkgPSB+SGFsZnRpbWUsIHR5cGUgPSAnYmFyJywgbmFtZSA9ICdIYWxmdGltZSBTY29yZScsIHdpZHRoID0gNjAwLCBoZWlnaHQgPSA1MDApICU+JSANCiAgYWRkX3RyYWNlKHkgPSB+RnVsbHRpbWUsIG5hbWUgPSAnRnVsbHRpbWUgU2NvcmUnKSAlPiUNCiAgbGF5b3V0KHlheGlzID0gbGlzdCh0aXRsZSA9ICdBbW91bnQnKSwgYmFybW9kZSA9ICdncm91cCcpDQoNCmZpZw0KYGBgDQpEaWUgb2JpZ2UgRXJrZW5udG5pcyBoYWJlbiB3aXIgaGllciBub2NoIGFscyBCYXJjaGFydCBkYXJnZXN0ZWxsdC4gRGFzIEhlaW10ZWFtIGdld2lubnQgYWxzbyBpbSBTY2huaXR0IHZpZWwgw7ZmdGVycywgYWxzIGRhcyBBdXN3w6RydHN0ZWFtLiANCg0KYGBge3J9DQojIE1lcmdlIEhUUiAmIEZUUiB0byBuZXcgY29sdW1uICdyZXN1bHQnDQpkZiRyZXN1bHQgPC0gcGFzdGUoZGYkSFRSLCBkZiRGVFIpDQoNCiMgRXhhbXBsZTogSCBIID0gaG9tZSB0ZWFtIGlzIHdpbm5pbmcgYXQgaGFsZnRpbWUgYW5kIGFsc28gd2lucyB0aGUgZ2FtZSBhdCBmdWxsdGltZQ0KDQpkZlssInJlc3VsdCIsIGRyb3A9RkFMU0VdDQpgYGANCmBgYHtyfQ0KIyBQbG90IGFsbCBkaWZmZXJlbnQgZ2FtZSBwcm9ncmVzc2VzIGFuZCB0aGVpciBhbW91bnQNCmRmX2NvdW50X3Jlc3VsdHMgPC0gZGYgJT4lDQogIGNvdW50KHJlc3VsdCkNCiAgDQpkZl9jb3VudF9yZXN1bHRzICU+JQ0KICBtdXRhdGUocmVzdWx0ID0gZmN0X3Jlb3JkZXIocmVzdWx0LCBuLCAuZGVzYyA9IFRSVUUpKSAlPiUNCiAgcGxvdF9seSh4ID0gfnJlc3VsdCwgeSA9IH5uLCB0ZXh0ID0gfm4sIHRleHRwb3NpdGlvbiA9ICdhdXRvJywgd2lkdGggPSA4MDAsIGhlaWdodCA9IDUwMCkgJT4lDQogIGFkZF9iYXJzKCkgJT4lDQogIGxheW91dCh4YXhpcyA9IGxpc3QodGl0bGUgPSAiR2FtZSBQcm9ncmVzcyIpLA0KICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIkFtb3VudCBvZiBHYW1lIFByb2dyZXNzZXMiKSwNCiAgICAgICAgIHRpdGxlID0gIkhvdyBhcmUgdGhlIGRpZmZlcmVudCBnYW1lIHByb2dyZXNzZXMgZGlzdHJpYnV0ZWQ/IikNCmBgYA0KSGllciB3b2xsdGVuIHdpciBoZXJhdXNmaW5kZW4sIHdpZSB3YWhyc2NoZWlubGljaCBkaWUgOSBtw7ZnbGljaGVuIFNwaWVsYXVzZ8OkbmdlbiBzaW5kIGJldm9yIGRhcyBTcGllbCDDvGJlcmhhdXB0IGJlZ2lubnQuIE1hbiBzaWVodCwgZGFzcyBkZXIgaMOkdWZpZ3N0ZSBTcGllbHZlcmxhdWYgZGFzICJIIEgiIGlzdC4gQWxzbywgZGFzcyBpbiBkZW4gbWVpc3RlbiBTcGllbGVuIGRhcyBIZWltdGVhbSB6dXIgSGFsYnplaXQgZsO8aHJ0IHVuZCBkaWUgRsO8aHJ1bmcgYmlzIHp1bSBTY2hsdXNzIGhhbHRlbiBrYW5uLiBEYXMgc2VsdGVuc3RlIFJlc3VsdGF0IHdhciwgZGFzcyBkYXMgSGVpbXRlYW0genVyIFBhdXNlIGdlZsO8aHJ0IGhhdCB1bmQgZGFzIFNwaWVsIGFtIEVuZGUgZG9jaCBub2NoIHZlcmxvci4gRGFzIGthbSBiZWkgMTUyMCBTcGVpZWxlbiBudXIgZ2VuYXUgMjd4IHZvci4gDQoNCmBgYHtyfQ0KIyBHcm91cCBieSBnYW1lIG91dGNvbWUgJiBjYWxjdWxhdGUgcHJvYmFiaWxpdHkgaW4gcGVyY2VudCBvZiBhbGwgb3V0Y29tZXMNCmRmX2NvdW50X3Jlc3VsdHNfcHJvYiA8LSBkZiAlPiUgDQogIGdyb3VwX2J5KHJlc3VsdCkgJT4lIA0KICBzdW1tYXJpc2UoY291bnRfcmVzdWx0ID0gcm91bmQobigpIC8gbnJvdyhkZikgKiAxMDAsIGRpZ2l0cyA9IDIpKQ0KDQojIFBsb3QgYWxsIGRpZmZlcmVudCBnYW1lIHByb2dyZXNzZXMgYW5kIHRoZWlyIHByb2JhYmlsaXR5DQpkZl9jb3VudF9yZXN1bHRzX3Byb2IgJT4lDQogIG11dGF0ZShyZXN1bHQgPSBmY3RfcmVvcmRlcihyZXN1bHQsIGNvdW50X3Jlc3VsdCwgLmRlc2MgPSBUUlVFKSkgJT4lDQogIHBsb3RfbHkoeCA9IH5yZXN1bHQsIHkgPSB+Y291bnRfcmVzdWx0LCB0ZXh0ID0gfmNvdW50X3Jlc3VsdCwgdGV4dHBvc2l0aW9uID0gJ2F1dG8nLCB3aWR0aCA9IDgwMCwgaGVpZ2h0ID0gNTAwKSAlPiUNCiAgYWRkX2JhcnMoKSAlPiUNCiAgbGF5b3V0KHhheGlzID0gbGlzdCh0aXRsZSA9ICJHYW1lIFByb2dyZXNzIiksDQogICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiUHJvYmFiaWxpdHkgb2YgR2FtZSBQcm9ncmVzcyAoJSkiKSwNCiAgICAgICAgIHRpdGxlID0gIkhvdyBhcmUgdGhlIGRpZmZlcmVudCBnYW1lIHByb2dyZXNzZXMgZGlzdHJpYnV0ZWQ/IikNCmBgYA0KRGVuIHNlbGJlbiBHcmFwaGVuIHdvbGx0ZW4gd2lyIG5vY2ggaW4gUHJvemVudGVuIGRhcnN0ZWxsZW4uIA0KDQpgYGB7cn0NCmRmX2NvdW50X3Jlc3VsdHMgJT4lDQogIHBsb3RfbHkobGFiZWxzID0gfnJlc3VsdCwgdmFsdWVzID0gfm4sIHRleHRpbmZvID0gInRleHQiLCB0ZXh0ID0gfm4pICU+JQ0KICBhZGRfcGllKGhvbGUgPSAwLjQsIGNvbG9yID0gSSgid2hpdGUiKSkgJT4lDQogIGxheW91dCh4YXhpcyA9IGxpc3QodGl0bGUgPSAiR2FtZSBQcm9ncmVzcyIpLA0KICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIlByb2JhYmlsaXR5ICUiKSwNCiAgICAgICAgIHRpdGxlID0gIkhvdyBhcmUgdGhlIGRpZmZlcmVudCBnYW1lIHByb2dyZXNzZXMgZGlzdHJpYnV0ZWQ/IikNCmBgYA0KSGllciBzaW5kIG5vY2hhbWxzIGRpZSBnbGVpY2hlbiBEYXRlbiwgYW5kZXJzIGRhcmdlc3RlbGx0IGluIGVpbmVtIERvbnV0Y2hhcnQuIEVzIGlzdCBpbnRlcmVzc2FudCwgd2VubiBtYW4gZWluaWdlIFNwZWlsdmVybMOkdWZlIGF1c2JsZW5kZXQuDQoNCmBgYHtyfQ0KZGZfY291bnRfcmVzdWx0c19wcm9iICU+JQ0KICBwbG90X2x5KGxhYmVscyA9IH5yZXN1bHQsIHZhbHVlcyA9IH5jb3VudF9yZXN1bHQpICU+JQ0KICBhZGRfcGllKGhvbGUgPSAwLjQsIGNvbG9yID0gSSgid2hpdGUiKSkgJT4lDQogIGxheW91dCh4YXhpcyA9IGxpc3QodGl0bGUgPSAiR2FtZSBQcm9ncmVzcyIpLA0KICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIlByb2JhYmlsaXR5ICUiKSwNCiAgICAgICAgIHRpdGxlID0gIldoYXQgaXMgdGhlIHByb2JhYmlsaXR5IG9mIGVhY2ggZ2FtZSBwcm9ncmVzcz8iKQ0KYGBgDQpJbiBkaWVzZW0gRG9udXRjaGFydCBzaWVodCBtYW4gZGllIFZlcnRlaWx1bmcgbm9jaG1hbHMgYW5kZXJzdCBkYXJnZXN0ZWxsdC4gDQoNCmBgYHtyfQ0KIyBDYWxjdWxhdGUgcHJvYmFiaWxpdHkgYmV0d2VlbiBoYWxmdGltZSAmIGZ1bGx0aW1lIGF3YXkgLyBkcmF3IC8gaG9tZSByZXN1bHRzDQpjYWxjX3Byb2IgPC0gZnVuY3Rpb24oZGYxLCBkZjIpIHsNCiAgcHJvYiA8LSByb3VuZCgoMTAwIC8gbnJvdyhkZjEpICogbnJvdyhkZjIpKSwgZGlnaXRzID0gMikNCiAgcmV0dXJuKHByb2IpDQp9DQpgYGANCg0KYGBge3J9DQojIEZpbHRlciBob21lIHRlYW1zIHdpbm5pbmcgYXQgaGFsZnRpbWUNCmRmX2h0X2hvbWUgPC0gZGYgJT4lIA0KICBmaWx0ZXIoSFRSID09ICJIIikNCg0KIyBGaWx0ZXIgaG9tZSB0ZWFtcyB3aW5uaW5nIGF0IGhhbGZ0aW1lICYgZnVsbHRpbWUNCmRmX2Z0X2hvbWUgPC0gZGZfaHRfaG9tZSAlPiUgDQogIGZpbHRlcihGVFIgPT0gIkgiKQ0KaG9tZV93aW5fcHJvYiA8LSBjYWxjX3Byb2IoZGZfaHRfaG9tZSwgZGZfZnRfaG9tZSkNCg0KY2F0KCJEaWUgV2FocnNjaGVpbmxpY2hrZWl0LCBkYXNzIGRhcyBIZWltdGVhbSBnZXdpbm50LCB3ZW5uIHNpZSB6dXIgSGFsYnplaXQgdm9ybmUgbGllZ2VuLCBiZXRyw6RndDogIiwgaG9tZV93aW5fcHJvYiwgIiUiKQ0KYGBgDQpgYGB7cn0NCiMgRmlsdGVyIGF3YXkgdGVhbXMgd2lubmluZyBhdCBoYWxmdGltZQ0KZGZfaHRfYXdheSA8LSBkZiAlPiUgDQogIGZpbHRlcihIVFIgPT0gIkEiKQ0KDQojIEZpbHRlciBhd2F5IHRlYW1zIHdpbm5pbmcgYXQgaGFsZnRpbWUgJiBmdWxsdGltZQ0KZGZfZnRfYXdheSA8LSBkZl9odF9hd2F5ICU+JSANCiAgZmlsdGVyKEZUUiA9PSAiQSIpDQoNCmF3YXlfd2luX3Byb2IgPC0gY2FsY19wcm9iKGRmX2h0X2F3YXksIGRmX2Z0X2F3YXkpDQoNCmNhdCgiRGllIFdhaHJzY2hlaW5saWNoa2VpdCwgZGFzcyBkYXMgQXVzd2VydHN0ZWFtIGdld2lubnQsIHdlbm4gc2llIHp1ciBIYWxiemVpdCB2b3JuZSBsaWVnZW4sIGJldHLDpGd0OiAiLCBhd2F5X3dpbl9wcm9iLCAiJSIpDQpgYGANCg0KYGBge3J9DQojIEZpbHRlciBkcmF3IGF0IGhhbGZ0aW1lDQpkZl9odF9kcmF3IDwtIGRmICU+JSANCiAgZmlsdGVyKEhUUiA9PSAiRCIpDQoNCiMgRmlsdGVyIGRyYXcgYXQgaGFsZnRpbWUgJiBmdWxsdGltZQ0KZGZfZnRfZHJhdyA8LSBkZl9odF9kcmF3ICU+JSANCiAgZmlsdGVyKEZUUiA9PSAiRCIpDQoNCmRyYXdfcHJvYiA8LSBjYWxjX3Byb2IoZGZfaHRfZHJhdywgZGZfZnRfZHJhdykNCg0KY2F0KCJEaWUgV2FocnNjaGVpbmxpY2hrZWl0LCBkYXNzIGVpbiBTcGllbCBpbiBlaW5lbSBVbmVudHNjaGllZGVuIGVuZGV0LCB3ZW5uIHNjaG9uIHp1ciBIYWxiemVpdCB1bmVudHNjaGllZGVuIHdhciwgYmV0csOkZ3Q6ICIsIGRyYXdfcHJvYiwgIiUiKQ0KYGBgDQoNCmBgYHtyfQ0KIyBGaWx0ZXIgZHJhdyBhdCBoYWxmdGltZSAmIHRoZSBob21lIHRlYW0gd2lubmluZyBhdCBmdWxsdGltZQ0KZGZfaHRfZHJhd19mdF9ob21lX3dpbiA8LSBkZl9odF9kcmF3ICU+JQ0KICBmaWx0ZXIoRlRSID09ICJIIikNCg0KaG9tZV93aW5fYWZ0ZXJfaHRfZHJhd19wcm9iIDwtIGNhbGNfcHJvYihkZl9odF9kcmF3LCBkZl9odF9kcmF3X2Z0X2hvbWVfd2luKQ0KDQpjYXQoIkRpZSBXYWhyc2NoZWlubGljaGtlaXQsIGRhc3MgZGFzIEhlaW10ZWFtIGdld2lubnQsIHdlbm4genVyIEhhbGJ6ZWl0IHVuZW50c2NoaWVkZW4gd2FyLCBiZXRyw6RndDogIiwgaG9tZV93aW5fYWZ0ZXJfaHRfZHJhd19wcm9iLCAiJSIpDQpgYGANCiMjIyBCZXN0w6R0aWd1bmcgZGVyIEh5cG90aGVzZQ0KDQpOdW4gd29sbGVuIHdpciBhYmVyIGRpZSBXYWhyc2NoZWlubGljaGtlaXQgd2lzc2VuLCBkYXNzIGRhcyB6dXIgSGFsYnplaXQgZsO8aHJlbmRlIFRlYW0gZGFzIFNwaWVsIGdld2lubnQuIEVnYWwgb2IgSGVpbSAtIG9kZXIgQXVzd8OkcnRzdGVhbS4NCg0KU29taXQga8O2bm5lbiB3aXIgYXVzIGRlbiAyIFdhaHJzY2hlaW5saWNoa2VpdGVuICJob21lX3dpbl9wcm9iIiB1bmQgImF3YXlfd2luX3Byb2IiIHVuc2VyZSBIeXBvdGhlc2Ugd2llIGZvbGd0IGJlc3TDpHRpZ2VuOiANCg0KYGBge3J9DQojIFByb2JhYmlsaXR5IHRoYXQgdGhlIHRlYW0gd2lubmluZyBhdCBoYWxmIHRpbWUgd2lucyB0aGUgZ2FtZQ0KaHRfZnRfd2luX3Byb2IgPC0gcm91bmQoKChob21lX3dpbl9wcm9iICogbnJvdyhkZl9mdF9ob21lKSkgKyAoYXdheV93aW5fcHJvYiAqIG5yb3coZGZfZnRfYXdheSkpKSAvIChucm93KGRmX2Z0X2hvbWUpICsgbnJvdyhkZl9mdF9hd2F5KSksIGRpZ2l0cyA9IDIpDQoNCmNhdCgiV2FocnNjaGVpbmxpY2hrZWl0LCBkYXNzIGRhcyBUZWFtLCB3ZWxjaGVzIHp1ciBIYWxiemVpdCBmw7xocnQsIGRlbiBNYXRjaCBnZXdpbm50OiAiLCBodF9mdF93aW5fcHJvYiwgIiUiKQ0KYGBgDQoNCmBgYHtyfQ0KIyBQbG90IEdhbWUgUHJvZ3Jlc3Mgb3ZlcnZpZXcNCmZpZyA8LSBwbG90X2x5KA0KICB5ID0gYygiSG9tZSB3aW5zIGFmdGVyIGxlYWRpbmcgYXQgSFQiLCAiQXdheSB3aW5zIGFmdGVyIGxlYWRpbmcgYXQgSFQiLCAiRHJhdyBhdCBGVCAmIEhUIiksIA0KICB4ID0gYyhob21lX3dpbl9wcm9iLCBhd2F5X3dpbl9wcm9iLCBkcmF3X3Byb2IpLA0KICB0eXBlID0gImJhciINCikNCg0KZmlnIDwtIGZpZyAlPiUgbGF5b3V0KHRpdGxlID0gIkdhbWUgUHJvZ3Jlc3MgT3ZlcnZpZXciLA0KICAgICAgICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gIlByb2JhYmlsaXR5IikpDQoNCmZpZw0KYGBgDQojIyMgRmF6aXQNCldpciBrb25udGVuIHVuc2VyZSBIeXBvdGhlc2UgYmVzdMOkdGlnZW4uIERhcyBUZWFtLCB3ZWxjaGVzIHp1ciBIYWxiemVpdCB2b3JuZSBsaWVndCwgZ2V3aW5udCB6dSA3OC40MSUuIEViZW5mYWxscyBpc3QgZGllIFdhaHJzY2hlaW5saWNoa2VpdCwgZGFzcyBkYXMgSGVpbXRlYW0gZ2V3aW5udCwgbmFjaCBlaW5lbSBVbmVudHNjaGllZGVuIHp1ciBIYWxiemVpdCwgMzguMDMlLiBXaXIgaMOkdHRlbiBkaWVzZW4gV2VydCBldHdhcyBow7ZoZXIgZXJ3YXJ0ZXQgdW5kIHNpbmQgw7xiZXIgZGFzIEVyZ2VibmlzIMO8YmVycmFzY2h0LiANCg0KDQojIyMgMi4gSHlwb3RoZXNlOg0KIyMjIERhcyBIZWltdGVhbSBoYXQgbWVociBTY2jDvHNzZSBhbHMgZGFzIEF1c3fDpHJ0c3RlYW0sIGFiZXIgZGFzIEF1c3dlcnRzdGVhbSBpc3QgZWZmaXppZW50ZXIuDQoNCmBgYHtyfQ0KIyBkZWYgdmFyaWFibGVzDQpuX3Nob3RzIDwtIGRmICU+JSANCiAgc3VtbWFyaXNlKA0KICAgIEhvbWUgPSBzdW0oSFMpLA0KICAgIEF3YXkgPSBzdW0oQVMpDQopDQoNCm5fc2hvdHMNCmBgYA0KRGVyIGVyc3RlIFRlaWwgZGVyIEh5cG90aGVzZSBpc3Qgc29taXQgYmVzdMOkdGlndC4gRGllIEhlaW10ZWFtcyBoYWJlbiB2aWVsIG1laHIgc2Now7xzc2UgYXVmcyBUb3IuIEltIER1cmNoc2Nobml0dCBzaW5kIGVzIGJlaSAxNTIwIFNwaWVsZW4gYWxzbyAxNC4wMSBTY2jDvHNzZSBkZXMgSGVpbXRlYW1zIHVuZCAxMS4yMSBTY2jDvHNzZSBkZXMgQXVzd2VydHN0ZWFtcy4NCg0KDQpgYGB7cn0NCiMgUGxvdCBGdWxsdGltZSBIb21lIFNob3RzIHZzIEhvbWUgR29hbHMgDQpwMSA8LSBkZiAlPiUNCiAgcGxvdF9seSh4ID0gfkZUSEcsIHkgPSB+SFMsIGNvbG9yYXhpcyA9ICdjb2xvcmF4aXMnKSAlPiUNCiAgYWRkX2hpc3RvZ3JhbTJkKG5iaW5zeSA9IDQwKQ0KDQojIFBsb3QgRnVsbHRpbWUgQXdheSBTaG90cyB2cyBBd2F5IEdvYWxzIA0KcDIgPC0gZGYgJT4lDQogIHBsb3RfbHkoeCA9IH5GVEFHLCB5ID0gfkFTLCBjb2xvcmF4aXMgPSAnY29sb3JheGlzJykgJT4lDQogIGFkZF9oaXN0b2dyYW0yZChuYmluc3kgPSA0MCkNCg0KIyBBZGQgYm90aCBwbG90cyB0b2dldGhlciB0byBidWlsZCBzdWJwbG90DQpzdWJwbG90KHAxLCBwMiwgbnJvd3MgPSAxLCBzaGFyZVggPSBGQUxTRSwgc2hhcmVZID0gRkFMU0UpICU+JQ0KICBsYXlvdXQoDQogICAgdGl0bGUgPSAiR29hbHMgdnMgU2hvdHMgT3ZlcnZpZXciLA0KICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICJIb21lIEdvYWxzIiksDQogICAgeGF4aXMyID0gbGlzdCh0aXRsZSA9ICJBd2F5IEdvYWxzIiksDQogICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIkhvbWUgU2hvdHMiKSwNCiAgICB5YXhpczIgPSBsaXN0KHRpdGxlID0gIkF3YXkgU2hvdHMiKSwNCiAgICBjb2xvcmF4aXM9bGlzdChjb2xvcnNjYWxlPSdKZXQnKQ0KICApDQpgYGANCkFuaGFuZCBkZXMgUGxvdHMgb2JlbiBpc3QgZ3V0IHp1IHNlaGVuLCBkYXNzIGRhcyBIZWltdGVhbSBvZnRtYWxzIDEtMiBUb3JlIHNjaGllc3N0IHVuZCA5LTE2IFRvcnNjaMO8c3NlIGF1ZndlaXN0LiBCZWltIEF1c3fDpHJ0c3RlYW0gc2llaHRzIGV0d2FzIGFuZGVycyBhdXM7IFNpZSBzY2hpZXNzZW4gZWhlciAwLTEgVG9yIHVuZCB3ZWlzZW4gZGFiZWkgNi0xMSBUb3JzY2jDvHNzZSBhdWYuDQoNCmBgYHtyfQ0KIyBGaXQgdGhlIHJlZ3Jlc3Npb24gbW9kZWwgb2YgRnVsbHRpbWUgSG9tZSBHb2FscyBvbiBIb21lIFNob3RzDQptIDwtIGxtKEZUSEcgfiBIUywgZGF0YSA9IGRmKQ0KDQojIENyZWF0ZSB0aGUgc2NhdHRlcnBsb3Qgd2l0aCBzbW9vdGhlcg0KZGYgJT4lDQogIHBsb3RfbHkoeCA9IH5IUywgeSA9IH5GVEhHKSAlPiUNCiAgYWRkX21hcmtlcnMoc2hvd2xlZ2VuZCA9IEZBTFNFKSAlPiUNCiAgYWRkX2xpbmVzKHkgPSB+Zml0dGVkKG0pKSAlPiUNCiAgbGF5b3V0KHRpdGxlID0gIkV4cGVjdGV0IGdvYWxzIGJ5IGhvbWUgc2hvdHMiKQ0KYGBgDQpBdWYgZGllc2VtIFBsb3QsIGthbm4gbWFuIGFuaGFuZCBkZXIgb3JhbmdlbiBMaW5pZSBzZWhlbiwgd2lldmllbGVuIFRvcmUgbWFuIGVyd2FydGVuIGthbm4sIGJlaSBlaW5lciBnZXdpc3NlbiBBbnphaGwgU2Now7xzc2UgZGVzIEhlaW10ZWFtcy4gWnVtIEJlaXNwaWVsOiBXZW5uIGRhcyBIZWltdGVhbSAyNSBTY2jDvHNzZSBhYmdpZWJ0LCBrYW5uIG1hbiBpbSBEdXJjaHNjaG5pdHQgbWl0IDIuMzEwIFRvcmVuIHJlY2huZW4uDQoNCmBgYHtyfQ0KIyBGaXQgdGhlIHJlZ3Jlc3Npb24gbW9kZWwgb2YgRnVsbHRpbWUgQXdheSBHb2FscyBvbiBBd2F5IFNob3RzDQptIDwtIGxtKEZUQUcgfiBBUywgZGF0YSA9IGRmKQ0KDQojIENyZWF0ZSB0aGUgc2NhdHRlcnBsb3Qgd2l0aCBzbW9vdGhlcg0KZGYgJT4lDQogIHBsb3RfbHkoeCA9IH5BUywgeSA9IH5GVEFHKSAlPiUNCiAgYWRkX21hcmtlcnMoc2hvd2xlZ2VuZCA9IEZBTFNFKSAlPiUNCiAgYWRkX2xpbmVzKHkgPSB+Zml0dGVkKG0pKSAlPiUNCiAgbGF5b3V0KHRpdGxlID0gIkV4cGVjdGV0IGdvYWxzIGJ5IGF3YXkgc2hvdHMiKQ0KYGBgDQpBdWYgZGllc2VtIFBsb3QsIGthbm4gbWFuIGFuaGFuZCBkZXIgb3JhbmdlbiBMaW5pZSBzZWhlbiwgd2lldmllbGVuIFRvcmUgbWFuIGVyd2FydGVuIGthbm4sIGJlaSBlaW5lciBnZXdpc3NlbiBBbnphaGwgU2Now7xzc2UgZGVzIEF1c3dlcnRzdGVhbXMuIFp1bSBCZWlzcGllbDogV2VubiBkYXMgQXVzd2VydHN0ZWFtIDI1IFNjaMO8c3NlIGFiZ2llYnQsIGthbm4gbWFuIGltIER1cmNoc2Nobml0dCBtaXQgMi4zODUgVG9yZW4gcmVjaG5lbi4gDQoNCmBgYHtyfQ0KIyBQbG90IDJkIEhpc3RvZ3JhbSAoSGVhdG1hcCkgd2l0aCBob21lIHNob3RzIHZzIGF3YXkgc2hvdHMNCmRmICU+JQ0KICBwbG90X2x5KHggPSB+SFMsIHkgPSB+QVMsIGNvbG9yYXhpcyA9ICdjb2xvcmF4aXMnKSAlPiUNCiAgYWRkX2hpc3RvZ3JhbTJkKG5iaW5zeCA9IDcwLCBuYmluc3kgPSA2MCkgJT4lDQogIGxheW91dChjb2xvcmF4aXM9bGlzdChjb2xvcnNjYWxlPSdKZXQnKSkNCmBgYA0KQW5oYW5kIGRpZXNlcyBQbG90cywgc2llaHQgbWFuIGRpZSBWZXJ0ZWlsdW5nIGRlciBTY2h1c3Now6R1Zmlna2VpdC4gSW4gZGVuIGFsbGVybWVpc3RlbiBTcGllbGVuLCBnZWJlbiBiZWlkZSBUZWFtcyAxMC0xNSBTY2jDvHNzZSBhYi4gRXMgZ2lidCBpbiBzZWx0ZW5lbiBGw6RsbGVuIGFiZXIgYXVjaCBTcGllbGUsIHdvIGRpZSBIZWltbWFuc2NoYWZ0IHZpZWwsIHZpZWwgbWVociBTY2jDvHNzZSBoYXQuIFpiIDF4IGhhdHRlIGRhcyBIZWltdGVhbSAzNyBTY2jDvHNzZSB1bmQgZGFzIEF1c3dlcnRzdGVhbSBOVVIgMyEgRGllc2VzIFNwaWVsIHdhciBMaXZlcnBvb2wgOiBFdmVydG9uIGltIEphaHIgMjAxNiB1bmQgTGl2ZXJwb29sIGdld2FubiA0OjAuIA0KYGBge3J9DQojY2FsY3VsYXRlIHRoZSBlZmZpY2llbmN5IG9mIHRoZSB0ZWFtcy4NCg0KZGZfZWZmaWNpZW5jeSA8LSBkZiAlPiUNCiAgc3VtbWFyaXNlKA0KICAgICJIb21lIEdvYWxzIHBlciBTaG90IiA9IHJvdW5kKHN1bShGVEhHKSAvIHN1bShIUyksZGlnaXRzID0gMyksDQogICAgIkhvbWUgR29hbHMgcGVyIFNob3Qgb24gVGFyZ2V0IiA9IHJvdW5kKHN1bShGVEhHKSAvIHN1bShIU1QpLGRpZ2l0cyA9IDMpLA0KICAgICJBd2F5IEdvYWxzIHBlciBTaG90IiA9IHJvdW5kKHN1bShGVEFHKSAvIHN1bShBUyksZGlnaXRzID0gMyksDQogICAgIkF3YXkgR29hbHMgcGVyIFNob3Qgb24gVGFyZ2V0IiA9IHJvdW5kKHN1bShGVEFHKSAvIHN1bShBU1QpLGRpZ2l0cyA9IDMpDQopDQpgYGANCg0KYGBge3J9DQojIFRyYW5zcG9zZSBkYXRhZnJhbWUNCnRfZGZfZWZmaWNpZW5jeSA8LSBkYXRhLmZyYW1lKCJQZXJjZW50IiA9IHQoZGZfZWZmaWNpZW5jeSkpDQpgYGANCg0KYGBge3J9DQojIFBsb3QgdGhlIGVmZmljaWVuY3kgaW4gYSBiYXJjaGFydC4NCmZpZyA8LSBwbG90X2x5KA0KICB5ID0gYygiSG9tZSBHb2FscyBwZXIgU2hvdCAiLCAiSG9tZSBHb2FscyBwZXIgU2hvdCBvbiBUYXJnZXQgIiwgIkF3YXkgR29hbHMgcGVyIFNob3QgIiwgIkF3YXkgR29hbHMgcGVyIFNob3Qgb24gVGFyZ2V0ICIpLA0KICB4ID0gdF9kZl9lZmZpY2llbmN5JFBlcmNlbnQsDQogIHR5cGUgPSAiYmFyIg0KKQ0KDQpmaWcgPC0gZmlnICU+JSBsYXlvdXQodGl0bGUgPSAiVGVhbSBFZmZpY2llbmN5IiwNCiAgICAgICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICJQcm9iYWJpbGl0eSIpKQ0KDQpmaWcNCmBgYA0KQW5oYW5kIGRpZXNlcyBEaWFncmFtcywga2FubiBtYW4gc2VoZW4sIGRhc3MgZGVyIHp3ZWl0ZSBUZWlsIHVuc2VyZXIgSHlwb3RoZXNlLCBsZWlkZXIgbmljaHQgc3RpbW10LiBEYXMgSGVpbXRlYW0gaXN0IGltIER1cmNoc2Nobml0dCBlZmZpemllbnRlciBhbHMgZGFzIEF1c3dlcnRzdGVhbS4gUHJvIFNjaHVzcyBhdWZzIFRvciwga2FubiBkYXMgSGVpbXRlYW0gbWl0IDAuMzI4IFRvcmVuIHJlY2huZW4uIERhcyBBdXN3ZXJ0c3RlYW0ga2FubiBwcm8gVG9yc2NodXNzIG51ciBtaXQgMC4zMTIgVG9yZW4gcmVjaG5lbi4gDQoNCiMjIyBGYXppdA0KV2lyIHNpbmQgw7xiZXJyYXNjaHQsIGRhc3MgZGFzIEhlaW10ZWFtIGV0d2FzIGVmZml6aWVudGVyIGlzdCwgYWxzIGRhcyBBdXN3ZXJ0c3RlYW0uIEFsbGVyZGluZ3MgaXN0IGRlciBVbnRlcnNjaGllZCBleHRyZW0ga25hcC4gV2FzIGFsbGVyZGluZ3Mgc3Bhbm5lbmQgenUgYmVvYmFjaHRlbiBpc3QsIGlzdCBkYXNzIGRhcyBIZWltdGVhbSBpbSBTY2huaXR0IGNhLiAxNCBTY2jDvHNzZSBoYXQgdW5kIGRhcyBBdXN3ZXJ0c3RlYW0gbnVyIGNhLiAxMS4gQWNodGV0IGV1Y2ggZG9jaCBiZWltIG7DpGNoc3RlbiBGdXNzYmFsbHNwaWVsIGRhcmF1Zi4gSWhyIGvDtm5udCBwcm8gU3BpZWwgYWxzbyBtaXQgY2EuIDI1IFNjaMO8c3NlbiByZWNobmVuLiBEYWJlaSBpc3QgZXMgd2FocnNjaGVpbmxpY2gsIGRhc3MgZGFzIEhlaW10ZWFtIGRhcyBTcGllbCBnZXdpbm50LCBhdWNoIHdlbm4genVyIEhhbGJ6ZWl0IG5vY2ggZWluIFVuZW50c2NoaWVkZW4gc3RlaHQuIA0KDQo=